6-2 nestjs内置日志模块Logger
日志模块概述
NestJS内置的日志模块(@nestjs/common/Logger
)是开发调试的核心工具,它提供了开箱即用的日志记录功能。这个模块的设计充分体现了NestJS"约定优于配置"的理念,让开发者能够快速上手而不需要复杂的配置。
核心特性
- 自动日志记录:
- 应用启动时的编译状态
- 接口路由注册信息
- HTTP请求处理过程
- 异常错误堆栈跟踪
- 多环境支持:
- 开发环境:详细日志输出
- 生产环境:可配置精简日志
- 零配置启动:
import { Logger } from '@nestjs/common'; const logger = new Logger('App');
typescript
技术实现细节
Logger模块基于观察者模式实现,内部维护了日志事件的发布-订阅机制。当调用logger.log()
等方法时,实际上是在触发日志事件,由默认的ConsoleLogger处理。
最佳实践
- 上下文命名规范:
// 推荐使用类名作为上下文 private readonly logger = new Logger(UserService.name);
typescript - 性能优化:
- 生产环境建议关闭debug/verbose级别日志
- 避免在循环中频繁记录日志
- 扩展方案:
// 自定义日志格式 class CustomLogger extends Logger { error(message: string, trace?: string) { super.error(`[CUSTOM] ${message}`, trace); } }
typescript
版本兼容性
NestJS版本 | 特性变化 |
---|---|
v7.x | 基础日志功能 |
v8.x | 新增日志级别过滤 |
v9.x | 优化性能,减少内存占用 |
💡 在最新的NestJS 10中,Logger模块进一步优化了异步日志处理能力,支持Promise链式调用。
常见问题解答
Q: 为什么我的日志没有输出? A: 请检查:
- main.ts中是否禁用了logger
- 日志级别设置是否过滤了当前日志
- 是否在bootstrap完成前调用了logger
Q: 如何记录对象类型数据? A: 使用JSON.stringify转换:
logger.debug(`User data: ${JSON.stringify(user)}`);
typescript
扩展阅读
这个模块虽然简单,但合理使用能极大提升开发效率和线上问题排查速度。建议在项目初期就规划好日志策略。
全局日志配置详解
NestJS提供了灵活的全局日志配置方案,让开发者可以根据不同环境需求精细控制日志输出行为。
1. 基础开关控制
完全禁用日志
const app = await NestFactory.create(AppModule, {
logger: false // 完全禁用所有日志输出
});
typescript
适用场景:
- 性能测试环境
- 特定场景下的基准测试
- 需要完全静默运行的场景
启用默认日志
const app = await NestFactory.create(AppModule, {
logger: true // 启用所有默认日志(相当于['log','error','warn','debug','verbose'])
});
typescript
2. 进阶配置方案
按级别过滤
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn'] // 只显示错误和警告
});
typescript
自定义日志处理器
const app = await NestFactory.create(AppModule, {
logger: new CustomLogger() // 使用自定义日志处理器
});
typescript
3. 动态环境配置
基于NODE_ENV的智能配置
const getLoggerConfig = () => {
switch (process.env.NODE_ENV) {
case 'production':
return ['error', 'warn'];
case 'test':
return false;
default:
return true;
}
};
const app = await NestFactory.create(AppModule, {
logger: getLoggerConfig()
});
typescript
多环境变量支持
const app = await NestFactory.create(AppModule, {
logger: process.env.LOG_LEVEL === 'silent'
? false
: process.env.LOG_LEVEL?.split(',') || true
});
typescript
4. 性能优化建议
- 生产环境配置:
logger: ['error'] // 只保留关键错误信息
typescript - 开发环境配置:
logger: ['log', 'error', 'warn', 'debug'] // 排除verbose级别
typescript - 测试环境配置:
logger: process.env.CI ? ['error'] : true // CI环境精简日志
typescript
5. 配置选项详解
配置值 | 类型 | 说明 |
---|---|---|
false | boolean | 完全禁用日志 |
true | boolean | 启用所有默认级别 |
Array<LogLevel> | string | 指定要启用的日志级别 |
LoggerService | object | 自定义日志服务实例 |
6. 最佳实践案例
企业级配置方案
const app = await NestFactory.create(AppModule, {
logger: process.env.NODE_ENV === 'production'
? ['error']
: process.env.DEBUG
? ['log', 'error', 'warn', 'debug', 'verbose']
: ['log', 'error', 'warn']
});
typescript
微服务场景配置
const app = await NestFactory.createMicroservice(AppModule, {
logger: process.env.SERVICE_TYPE === 'core'
? ['error', 'warn']
: ['log', 'error']
});
typescript
7. 常见问题排查
问题1:日志配置不生效怎么办?
- 检查配置是否在
NestFactory.create()
中正确设置 - 确认没有在其他地方覆盖了日志配置
- 检查环境变量是否正确加载
问题2:如何临时开启详细日志?
// 运行时动态修改
app.useLogger(new Logger('debug', { debug: true }));
typescript
问题3:自定义日志和全局配置冲突?
// 解决方案:在自定义Logger中继承默认行为
class MyLogger extends Logger {
constructor() {
super('MyApp', { timestamp: true });
}
}
typescript
8. 版本兼容说明
NestJS版本 | 特性变化 |
---|---|
v7 | 基础配置支持 |
v8 | 增加数组形式级别配置 |
v9+ | 支持自定义LoggerService注入 |
通过合理配置全局日志,可以显著提升应用的可观察性,同时避免生产环境下的日志爆炸问题。建议结合APM工具实现更完善的监控方案。
日志分级控制详解
NestJS的日志系统采用精细化的分级控制机制,让开发者可以根据不同环境和需求灵活配置日志输出级别。
1. 完整的日志等级体系
等级 | 颜色代码 | 控制台显示 | 使用场景 | 推荐环境 |
---|---|---|---|---|
log | \x1b[32m | 绿色 | 常规业务流程记录,如服务启动、接口访问等 | 所有环境 |
error | \x1b[31m | 红色 | 系统级错误、未捕获异常、数据库连接失败等关键问题 | 必须保留 |
warn | \x1b[33m | 黄色 | 潜在风险警告,如API弃用提示、配置参数不合法等 | 生产环境建议 |
debug | \x1b[34m | 蓝色 | 开发调试信息,如SQL语句、中间件处理过程等 | 开发/测试环境 |
verbose | \x1b[37m | 灰色 | 极其详细的跟踪信息,如每个请求的完整头信息、微服务间通信细节等 | 特定调试场景 |
fatal * | \x1b[41m | 红底白字 | 导致应用崩溃的致命错误(需自定义实现) | 关键生产系统 |
*注:
fatal
级别为建议扩展级别,非NestJS原生支持
2. 等级配置的进阶用法
动态等级调整
// 根据请求头动态调整日志级别
app.use((req, res, next) => {
if (req.headers['x-debug-mode']) {
Logger.overrideLogger(['debug', 'verbose']);
}
next();
});
typescript
模块级差异化配置
// user.module.ts
@Module({
providers: [
{
provide: Logger,
useValue: new Logger('UserModule', ['error', 'warn'])
}
]
})
export class UserModule {}
typescript
3. 类型安全的高级配置
NestJS使用TypeScript字面量类型确保配置安全:
type LogLevel = 'log' | 'error' | 'warn' | 'debug' | 'verbose';
// 这种配置会引发类型错误
logger: ['info'] // TS Error: 类型"info"不可分配给类型"LogLevel"
// 合法配置示例
logger: ['error', 'warn'] as const; // 使用as const获得最精确的类型推断
typescript
4. 生产环境推荐配置方案
const productionLoggerConfig: LogLevel[] = [
'error', // 必须保留
'warn', // 建议保留
process.env.ENABLE_AUDIT_LOG === 'true' ? 'log' : null
].filter(Boolean) as LogLevel[];
typescript
5. 等级关联的元数据配置
interface LogMetadata {
level: LogLevel;
timestamp: Date;
context: string;
stack?: string;
}
class EnhancedLogger extends Logger {
log(message: string, context?: string) {
const metadata: LogMetadata = {
level: 'log',
timestamp: new Date(),
context: context || this.context
};
super.log(JSON.stringify({ message, metadata }));
}
}
typescript
6. 性能优化建议
- 等级过滤优先级:
- 敏感信息过滤:
logger.debug(`User login: ${maskSensitiveData(user)}`);
typescript
7. 跨平台兼容方案
// 适配不同环境的颜色输出
function getColorCode(level: LogLevel): string {
if (process.platform === 'win32') {
return ''; // Windows终端去掉颜色代码
}
return {
error: '\x1b[31m',
warn: '\x1b[33m',
// ...其他等级
}[level];
}
typescript
8. 监控系统集成示例
// 将error日志自动上报到Sentry
logger.error = (message: string, trace?: string) => {
Sentry.captureException(new Error(message));
super.error(message, trace);
};
typescript
9. 常见问题解决方案
问题1:如何临时提升日志级别?
# 启动时指定调试级别
LOG_LEVEL=debug,verbose npm start
bash
问题2:日志级别不生效?
- 检查中间件是否覆盖了Logger配置
- 确认没有多实例Logger冲突
- 验证环境变量是否正确加载
问题3:如何添加自定义级别?
// 扩展LogLevel类型
type ExtendedLogLevel = LogLevel | 'fatal';
typescript
通过合理配置日志分级,可以实现:
- 生产环境关键问题快速定位
- 开发环境完整调试信息
- 测试环境精准问题复现
- 灵活适应各种监控系统需求
建议结合CI/CD流水线,实现不同部署阶段自动化的日志级别配置。
Logger实战应用深度解析
1. 基础实例化高级用法
带配置参数的实例化
const logger = new Logger('APP_BOOTSTRAP', {
timestamp: true, // 显示时间戳
colorize: true, // 启用颜色
printLevel: true // 打印日志级别
});
logger.log(`服务启动完成,端口:${port}`);
// 输出示例:[2023-08-20T10:00:00.000Z] [INFO] [APP_BOOTSTRAP] 服务启动完成,端口:3000
typescript
多上下文关联
const appLogger = new Logger('APP');
const dbLogger = appLogger.createChildLogger('DB');
dbLogger.debug('数据库连接池初始化');
// 输出:[APP:DB] 数据库连接池初始化
typescript
2. Controller集成最佳实践
自动依赖注入方案
@Controller('users')
export class UserController {
constructor(
@Inject(Logger) private readonly logger: Logger
) {
this.logger.setContext(UserController.name);
}
}
typescript
请求生命周期跟踪
@Get(':id')
async getUser(@Param('id') id: string) {
this.logger.debug(`开始处理用户 ${id} 请求`);
const timer = Date.now();
try {
const user = await this.service.getUser(id);
this.logger.log(`请求完成,耗时 ${Date.now() - timer}ms`);
return user;
} catch (error) {
this.logger.error(`处理失败: ${error.stack}`);
throw error;
}
}
typescript
3. Service层日志规范
业务操作日志
@Injectable()
export class UserService {
private readonly logger = new Logger(UserService.name);
async createUser(dto: CreateUserDto) {
this.logger.verbose(`创建用户 ${dto.username}`);
// ...业务逻辑
this.logger.log(`用户 ${user.id} 创建成功`);
}
}
typescript
事务跟踪示例
async transferFunds(fromId: string, toId: string, amount: number) {
const transactionId = uuidv4();
this.logger.debug(`[${transactionId}] 开始资金转账`);
try {
// ...转账逻辑
this.logger.log(`[${transactionId}] 转账完成`);
} catch (error) {
this.logger.error(`[${transactionId}] 转账失败: ${error.message}`);
throw error;
}
}
typescript
4. 中间件日志集成
请求日志中间件
@Injectable()
export class RequestLoggerMiddleware implements NestMiddleware {
private readonly logger = new Logger('HTTP');
use(req: Request, res: Response, next: NextFunction) {
const { method, originalUrl } = req;
this.logger.debug(`[Incoming] ${method} ${originalUrl}`);
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
this.logger.log(`[Completed] ${method} ${originalUrl} - ${res.statusCode} (${duration}ms)`);
});
next();
}
}
typescript
5. 异常过滤器日志
全局异常日志
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger('EXCEPTION');
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
this.logger.error(
`Path: ${request.url}\n` +
`Method: ${request.method}\n` +
`Error: ${exception instanceof Error ? exception.stack : exception}`
);
// ...返回错误响应
}
}
typescript
6. 定时任务日志
任务执行跟踪
@Cron('0 0 * * *')
export class DailyReportJob {
private readonly logger = new Logger(DailyReportJob.name);
async handle() {
this.logger.log('开始生成日报');
try {
// ...报表生成逻辑
this.logger.log('日报生成完成');
} catch (error) {
this.logger.error(`日报生成失败: ${error.message}`);
}
}
}
typescript
7. 微服务场景日志
跨服务调用追踪
@MessagePattern('ORDER_CREATED')
async handleOrderCreated(data: OrderDto) {
const traceId = data.metadata?.traceId || uuidv4();
this.logger.debug(`[${traceId}] 开始处理订单创建事件`);
try {
// ...处理逻辑
this.logger.log(`[${traceId}] 订单处理完成`);
} catch (error) {
this.logger.error(`[${traceId}] 处理失败: ${error.stack}`);
throw error;
}
}
typescript
8. 日志上下文增强技巧
请求上下文注入
// 自定义装饰器
export const LogContext = createParamDecorator((_, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return {
userId: request.user?.id,
requestId: request.headers['x-request-id']
};
});
// 在Controller中使用
@Get()
getUsers(@LogContext() context: any) {
this.logger.log(`请求用户数据 [用户ID: ${context.userId}]`);
}
typescript
9. 性能关键路径日志
关键操作计时
function withPerformanceLog(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
const logger = new Logger(`${target.constructor.name}.${propertyKey}`);
descriptor.value = async function (...args: any[]) {
const start = Date.now();
logger.debug(`开始执行`);
try {
const result = await originalMethod.apply(this, args);
logger.log(`执行完成 (${Date.now() - start}ms)`);
return result;
} catch (error) {
logger.error(`执行失败 (${Date.now() - start}ms): ${error.message}`);
throw error;
}
};
return descriptor;
}
// 使用装饰器
@withPerformanceLog
async complexCalculation(input: number) {
// ...复杂计算
}
typescript
10. 测试环境特殊处理
测试断言辅助
class TestLogger extends Logger {
public logs: string[] = [];
log(message: string) {
this.logs.push(message);
super.log(message);
}
}
// 在测试中使用
describe('UserService', () => {
let testLogger: TestLogger;
beforeEach(() => {
testLogger = new TestLogger('TEST');
userService.setLogger(testLogger);
});
it('should log creation', () => {
await userService.createUser(testData);
expect(testLogger.logs).toContain('用户创建成功');
});
});
typescript
最佳实践总结
- 上下文命名规范:
- 服务类:
ServiceClassName
- 控制器:
ControllerName
- 中间件:
MiddlewarePurpose
- 定时任务:
JobName
- 服务类:
- 日志级别选择:
- 常规流程:
log
- 异常情况:
error
- 调试信息:
debug
- 敏感操作:
verbose
+ 数据脱敏
- 常规流程:
- 性能敏感场景:
- 高频操作避免同步日志
- 循环内日志考虑采样率
- 生产环境关闭debug/verbose
- 分布式追踪:
- 注入请求ID/traceID
- 跨服务传递上下文
- 统一日志格式
通过以上实践,可以构建出具有良好可观测性的应用系统,有效平衡调试需求和运行时性能。
适用场景与局限深度解析
内置Logger的核心能力
主要技术局限
企业级扩展方案对比
方案 | 核心优势 | 适用场景 | 性能影响 | 集成复杂度 |
---|---|---|---|---|
Winston | 多传输支持(文件、数据库、云服务) | 需要长期日志存储的企业应用 | 中 | 高 |
Pino | 极致性能(比Winston快4-5倍) | 高并发IO密集型应用 | 低 | 中 |
NestJS-Pino | 深度Nest集成,开箱即用 | 需要快速上手的项目 | 低 | 低 |
自定义适配器 | 完全自主控制 | 特殊日志协议需求 | 可变 | 极高 |
Winston实战配置示例
// winston.config.ts
import { utilities as nestWinstonUtils } from 'nest-winston';
import * as winston from 'winston';
export const winstonConfig = {
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
nestWinstonUtils.format.nestLike()
)
}),
new winston.transports.File({
filename: 'logs/application.log',
maxsize: 1024 * 1024 * 5 // 5MB
})
]
};
// main.ts
app.useLogger(winston.createLogger(winstonConfig));
typescript
Pino高性能方案
// pino.config.ts
import { Logger } from 'nestjs-pino';
@Module({
imports: [LoggerModule.forRoot()],
providers: [Logger]
})
export class AppModule {}
// controller中使用
@Controller()
export class AppController {
constructor(private readonly logger: Logger) {}
@Get()
getData() {
this.logger.info('请求处理开始');
// ...业务逻辑
this.logger.info({ duration }, '请求处理完成');
}
}
typescript
混合日志策略
云原生方案推荐
- AWS CloudWatch集成
import { CloudWatchLogs } from 'aws-sdk';
const cloudwatchLogger = new winston.transports.CloudWatchLogs({
logGroupName: 'my-app',
logStreamName: 'api-service'
});
typescript
- Datadog APM对接
import { datadog } from 'pino-datadog';
const pino = require('pino')({
transport: {
pipeline: [{
target: 'pino-datadog-transport',
options: { ddClientConf: { site: 'datadoghq.com' } }
}]
}
});
typescript
性能优化技巧
- 异步日志写入
const logger = pino({
transport: {
target: 'pino/file',
options: { destination: 'logs/app.log', mkdir: true },
worker: {
interval: 1000, // 1秒批量写入一次
maxBufferSize: 1024 * 1024 // 1MB缓冲区
}
}
});
typescript
- 敏感数据过滤
const secureLogger = winston.createLogger({
format: winston.format((info) => {
if (info.message.includes('password')) {
info.message = info.message.replace(/password=.*?(?=\s|$)/, 'password=***');
}
return info;
})()
});
typescript
迁移路径建议
监控指标集成
// 日志量监控
const logger = new Proxy(originalLogger, {
get(target, prop) {
if (['log','error','warn'].includes(prop)) {
metrics.increment('log_count', { level: prop });
}
return target[prop];
}
});
typescript
常见问题解决方案
问题1:如何保留内置Logger的简洁性又需要文件存储?
// 混合使用方案
const logger = new Logger('APP');
const fileTransport = new winston.transports.File({ filename: 'logs/hybrid.log' });
logger.log = (message: string) => {
fileTransport.log('info', message);
super.log(message);
};
typescript
问题2:生产环境日志量过大怎么办?
- 方案1:启用日志轮转
# 使用logrotate工具
/var/log/my-app/*.log {
daily
rotate 7
compress
missingok
}
bash
- 方案2:实现采样率控制
logger.debug = (message: string) => {
if (Math.random() < 0.1) { // 10%采样率
super.debug(message);
}
};
typescript
通过合理的架构设计和工具选型,可以构建出既满足开发调试需求,又能适应生产环境要求的完整日志解决方案。建议根据团队规模和应用复杂度选择合适的演进路径。
高级自定义方案深度解析
1. 自定义Logger的完整实现方案
企业级文件日志示例
// file-logger.service.ts
import { LoggerService } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
export class FileLogger implements LoggerService {
private readonly logPath = path.join(__dirname, '../../logs');
constructor() {
this.ensureLogDirectory();
}
private ensureLogDirectory() {
if (!fs.existsSync(this.logPath)) {
fs.mkdirSync(this.logPath, { recursive: true });
}
}
private writeLog(level: string, message: string, context?: string) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${context ? `[${context}]` : ''} ${message}\n`;
fs.appendFileSync(path.join(this.logPath, 'application.log'), logEntry);
}
log(message: string, context?: string) {
this.writeLog('info', message, context);
}
error(message: string, trace?: string, context?: string) {
this.writeLog('error', `${message}${trace ? `\n${trace}` : ''}`, context);
}
warn(message: string, context?: string) {
this.writeLog('warn', message, context);
}
debug(message: string, context?: string) {
this.writeLog('debug', message, context);
}
verbose(message: string, context?: string) {
this.writeLog('verbose', message, context);
}
}
typescript
数据库日志实现
// db-logger.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { LogEntry } from './log-entry.entity';
@Injectable()
export class DbLogger implements LoggerService {
constructor(
@InjectRepository(LogEntry)
private readonly logRepository: Repository<LogEntry>
) {}
async log(message: string, context?: string) {
await this.saveLog('info', message, context);
}
// 其他方法实现类似...
private async saveLog(level: string, message: string, context?: string) {
const entry = this.logRepository.create({
level,
message,
context,
timestamp: new Date()
});
await this.logRepository.save(entry);
}
}
typescript
2. 动态热更新高级技巧
条件热切换实现
// logger-manager.service.ts
@Injectable()
export class LoggerManager {
private currentLogger: LoggerService;
constructor(
private readonly fileLogger: FileLogger,
private readonly consoleLogger: Logger
) {
this.currentLogger = consoleLogger;
}
switchToFileLogger() {
Logger.overrideLogger(this.fileLogger);
this.currentLogger = this.fileLogger;
}
switchToConsoleLogger() {
Logger.overrideLogger(this.consoleLogger);
this.currentLogger = this.consoleLogger;
}
getCurrentLogger() {
return this.currentLogger;
}
}
typescript
基于配置的热更新
// config-based-logger.ts
export class ConfigurableLogger implements LoggerService {
private strategy: LoggerService;
constructor(configService: ConfigService) {
this.updateStrategy(configService.get('LOG_TYPE'));
configService.onChange('LOG_TYPE', (newValue) => {
this.updateStrategy(newValue);
});
}
private updateStrategy(type: string) {
this.strategy = type === 'file' ? new FileLogger() : new Logger();
}
log(message: string, context?: string) {
this.strategy.log(message, context);
}
// 其他方法委托给当前策略...
}
typescript
3. 性能优化型Logger实现
异步批量写入Logger
// async-batch-logger.service.ts
export class AsyncBatchLogger implements LoggerService {
private buffer: string[] = [];
private flushInterval: NodeJS.Timeout;
private readonly maxBufferSize = 1000;
constructor(private readonly filePath: string) {
this.flushInterval = setInterval(() => this.flush(), 5000);
}
private async flush() {
if (this.buffer.length === 0) return;
const toWrite = this.buffer.join('\n');
this.buffer = [];
await fs.promises.appendFile(this.filePath, toWrite + '\n');
}
log(message: string) {
this.buffer.push(`[LOG] ${message}`);
if (this.buffer.length >= this.maxBufferSize) {
this.flush();
}
}
onApplicationShutdown() {
clearInterval(this.flushInterval);
return this.flush();
}
// 其他日志级别方法...
}
typescript
4. 分布式追踪集成方案
请求链式追踪Logger
// trace-logger.service.ts
export class TraceLogger implements LoggerService {
private readonly requestStore = new AsyncLocalStorage<{ traceId: string }>();
runWithTrace(traceId: string, callback: () => void) {
this.requestStore.run({ traceId }, callback);
}
private getTraceContext() {
const store = this.requestStore.getStore();
return store ? `[TraceID: ${store.traceId}]` : '';
}
log(message: string, context?: string) {
const traceContext = this.getTraceContext();
console.log(`${traceContext} [${context}] ${message}`);
}
// 其他方法实现...
}
typescript
5. 多通道日志路由
智能路由Logger实现
// router-logger.service.ts
export class RouterLogger implements LoggerService {
constructor(
private readonly criticalLogger: LoggerService,
private readonly debugLogger: LoggerService
) {}
log(message: string, context?: string) {
const target = context?.includes('DB') ? this.criticalLogger : this.debugLogger;
target.log(message, context);
}
error(message: string, trace?: string, context?: string) {
this.criticalLogger.error(message, trace, context);
}
// 其他方法实现...
}
typescript
6. 验证与测试方案
Logger测试工具类
// test-logger.ts
export class TestLogger implements LoggerService {
public logs: { level: string; message: string; context?: string }[] = [];
log(message: string, context?: string) {
this.logs.push({ level: 'log', message, context });
}
error(message: string, trace?: string, context?: string) {
this.logs.push({ level: 'error', message: `${message} ${trace || ''}`, context });
}
// 其他方法实现...
clear() {
this.logs = [];
}
findByLevel(level: string) {
return this.logs.filter(entry => entry.level === level);
}
}
typescript
7. 生产环境最佳实践
优雅关闭处理
// graceful-shutdown.ts
export class GracefulLogger extends Logger {
private pendingWrites = 0;
async log(message: string) {
this.pendingWrites++;
await someAsyncWrite(message);
this.pendingWrites--;
}
async waitForPendingWrites() {
while (this.pendingWrites > 0) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
}
// 在关闭钩子中
app.enableShutdownHooks();
app.useLogger(new GracefulLogger());
process.on('SIGTERM', async () => {
await app.get(GracefulLogger).waitForPendingWrites();
process.exit(0);
});
typescript
8. 高级配置选项
动态日志级别控制
// dynamic-level-logger.ts
export class DynamicLevelLogger implements LoggerService {
private level: LogLevel = 'log';
setLevel(newLevel: LogLevel) {
this.level = newLevel;
}
private shouldLog(callerLevel: LogLevel) {
const levels: LogLevel[] = ['verbose', 'debug', 'log', 'warn', 'error'];
return levels.indexOf(callerLevel) >= levels.indexOf(this.level);
}
log(message: string, context?: string) {
if (this.shouldLog('log')) {
console.log(`[${context}] ${message}`);
}
}
// 其他方法实现...
}
typescript
9. 可视化监控集成
Prometheus指标集成
// metrics-logger.ts
export class MetricsLogger implements LoggerService {
constructor(
private readonly wrappedLogger: LoggerService,
private readonly counter: Counter<string>
) {}
log(message: string, context?: string) {
this.counter.inc({ level: 'info' });
this.wrappedLogger.log(message, context);
}
error(message: string, trace?: string, context?: string) {
this.counter.inc({ level: 'error' });
this.wrappedLogger.error(message, trace, context);
}
// 其他方法实现...
}
typescript
10. 架构设计建议
通过以上方案,开发者可以构建出满足各种复杂场景需求的企业级日志系统,同时保持与NestJS生态的完美集成。建议根据实际业务需求选择合适的技术组合,并在项目早期就建立完善的日志规范。
↑